var Extended = function(superFn, fn){
	return function(){
		superFn.apply(this, arguments);
		return fn.apply(this, arguments);
	};
};
// --------------------------------------------------------------------------------------------
var Exception = function(msg) {
	if (msg) {
		this._message = new String(msg);
	} else {
		this._message = "";
	}
	this._type = 'Exception';
	
	this.toString = function() {
		var msg = this._type + ': "' + this._message + '".';
		alert(msg);
		return msg;
	};
};
var IllegalStateException = new Extended(Exception, function(){
	this._type = 'IllegalStateException';
});
var IllegalArgumentException = new Extended(Exception, function(){
	this._type = 'IllegalStateException';
});
//------------------------------------------------------------------------------
var Check = {};
Check.notNull = function(object, name){
	var aName = "Object";
	if(name){
		aName = name;
	}
	if(!object){
		throw new IllegalArgumentException(aName + " cannot be null");			
	}
};
Check.isArray = function(object){
	if(!object instanceof Array){
		throw new IllegalArgumentException("Object " + object + " is not Array");
	}
};
Check.isFunction = function(object){
	if(!object instanceof Function){
		throw new IllegalArgumentException("Object " + object + " is not a Function");
	}
};
Check.inArray = function(array, value){
    var i = array.length;
    var found = false;
    while (i-- && ! found) {
       if (array[i] === value) {
           found = true;
       }
    }
    if(!found){
    	throw new IllegalStateException("Value '" + value + "' not found in array " + array);
    }
};

//-------------------------------------------------------------------------------
var RestService = {};
RestService.send = function(config) {
		Check.notNull(config);
		Check.notNull(config.type);
		Check.notNull(config.url);
		Check.notNull(config.onSuccess);
		Check.isFunction(config.onSuccess);
		if(config.onError){
			Check.isFunction(config.onError);
		}
		if(config.onAfter){
			Check.isFunction(config.onAfter);
		}
		
		var jsonData = null;
		var contentType = null;
		if(config.type != "GET" && config.data){
			jsonData = JSON.stringify(config.data, null, 2);
			contentType = "application/json; charset=utf-8";
		}
		else{
			jsonData = config.data;
		}
		$.ajax({
			url : config.url,
			type : config.type,
			contentType : contentType,
			dataType : 'json',
			data : jsonData,
			success : function(data) {
				config.onSuccess(data);
				if(config.onAfter){
					config.onAfter();
				}
			},
			error : function(response) {
				config.onError(response.status, response.responseText);
				if(config.onAfter){
					config.onAfter();
				}
			}
		});
	};
//-----------------------------------------------------------------------------------------------
var Subscribable = function(fn){
    Check.notNull(fn);
    Check.isFunction(fn);
    
	var func = function(){
        var returnValue = fn.apply(this, arguments);
        for(var i = 0; i < func._subscribers.length; i++){
			func._subscribers[i].apply(this, [returnValue]);
		}
        return returnValue;
    };
    func._subscribers = new Array();
    func.subscribe = function(callback){
    	Check.notNull(callback);
    	Check.isFunction(callback);
    	
    	func._subscribers.push(callback);
	};
    return func;
};
var FixedFunction = function(objThis, fn){
	Check.notNull(objThis);
	Check.notNull(fn);
    Check.isFunction(fn);
    
	return function(){
		return fn.apply(objThis, arguments);
	};
};